//---------------------------------------------------------------------------
// <copyright file="RibbonComboBox.cs" company="Microsoft Corporation">
//     Copyright (C) Microsoft Corporation.  All rights reserved.
// </copyright>
//---------------------------------------------------------------------------

namespace Microsoft.Windows.Controls.Ribbon
{
    #region Using declarations

    using System;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Input;

    #endregion

    /// <summary>
    ///   A ComboBox which implements IRibbonControl so that it can be placed in the Ribbon, and
    ///   ICommandSource so that it has the ability to execute RibbonCommands via its items. It
    ///   also implements ToolTip property coercion to allow use of Ribbon tooltips.
    /// </summary>
    public class RibbonComboBox : ComboBox, IRibbonControl, ICommandSource
    {
        #region Constructors

        /// <summary>
        ///   Initializes static members of the RibbonComboBox class.  Here we override the
        ///   default style, a coerce callback, and allow tooltips to be shown for disabled controls.
        /// </summary>
        static RibbonComboBox()
        {
            Type ownerType = typeof(RibbonComboBox);

            DefaultStyleKeyProperty.OverrideMetadata(ownerType, new FrameworkPropertyMetadata(ownerType));
            ToolTipProperty.OverrideMetadata(ownerType, new FrameworkPropertyMetadata(null, new CoerceValueCallback(CoerceToolTip)));
            ToolTipService.ShowOnDisabledProperty.OverrideMetadata(ownerType, new FrameworkPropertyMetadata(true));
        }

        #endregion

        #region Public Properties

        /// <summary>
        ///   Gets or sets the Command that will be executed when the command source is invoked.
        /// </summary>
        public ICommand Command
        {
            get { return (ICommand)GetValue(CommandProperty); }
            set { SetValue(CommandProperty, value); }
        }

        /// <summary>
        ///   Using a DependencyProperty as the backing store for CommandProperty.  This enables animation, styling, binding, etc...
        /// </summary>
        public static readonly DependencyProperty CommandProperty =
                    DependencyProperty.Register(
                            "Command",
                            typeof(ICommand),
                            typeof(RibbonComboBox),
                            new FrameworkPropertyMetadata(new PropertyChangedCallback(OnCommandChanged)));

        /// <summary>
        ///   Gets or sets a user defined data value that can be passed to the command when it is executed.
        /// </summary>
        public object CommandParameter
        {
            get { return (object)GetValue(CommandParameterProperty); }
            set { SetValue(CommandParameterProperty, value); }
        }

        /// <summary>
        ///   Using a DependencyProperty as the backing store for CommandParameterProperty.  This enables animation, styling, binding, etc...
        /// </summary>
        public static readonly DependencyProperty CommandParameterProperty =
                    DependencyProperty.Register(
                            "CommandParameter",
                            typeof(object),
                            typeof(RibbonComboBox),
                            new FrameworkPropertyMetadata(null));

        /// <summary>
        ///   Gets or sets the object that the command is being executed on.
        /// </summary>
        public IInputElement CommandTarget
        {
            get { return (IInputElement)GetValue(CommandTargetProperty); }
            set { SetValue(CommandTargetProperty, value); }
        }

        /// <summary>
        ///   Using a DependencyProperty as the backing store for CommandTargetProperty.  This enables animation, styling, binding, etc...
        /// </summary>
        public static readonly DependencyProperty CommandTargetProperty =
                    DependencyProperty.Register(
                            "CommandTarget",
                            typeof(IInputElement),
                            typeof(RibbonComboBox),
                            new FrameworkPropertyMetadata(null));

        #endregion

        #region Public Methods

        /// <summary>
        ///   If the developer hasn't assigned their own tooltip, Create and attach a new RibbonToolTip.
        /// </summary>
        /// <param name="d">
        ///   The RibbonComboBox that the ToolTip property exists on.  When the callback is invoked,
        ///   the property system will pass this value.
        /// </param>
        /// <param name="value">The new value of the ToolTip property, prior to any coercion attempt.</param>
        /// <returns>The coerced value of the ToolTip property.</returns>
        public static object CoerceToolTip(DependencyObject d, object value)
        {
            if (value == null)
            {
                RibbonComboBox comboBox = (RibbonComboBox)d;
                RibbonCommand command = comboBox.Command as RibbonCommand;
                if (command != null &&
                    (!string.IsNullOrEmpty(command.ToolTipTitle) || !string.IsNullOrEmpty(command.ToolTipDescription) || command.ToolTipImageSource != null))
                {
                    value = new RibbonToolTip(command);
                }
            }

            return value;
        }

        #endregion

        #region Internal Methods

        /// <summary>
        ///     Called from the highlighted RibbonComboBoxItem to send commands.
        /// </summary>
        /// <param name="action">The action that command is taking.</param>
        /// <param name="item">The RibbonComboBoxItem signaling that the command should be invoked.</param>
        internal void ExecuteCommandFromComboBoxItem(RibbonCommandAction action, RibbonComboBoxItem item)
        {
            RibbonCommandParameter parameter = new RibbonCommandParameter()
            {
                CommandParameter = this.CommandParameter,
                Action = action,
                ActionParameter = item,
            };

            CommandHelpers.ExecuteCommandSource(parameter, this);
        }

        #endregion

        #region Protected Methods

        /// <summary>
        ///   Return true if the item is (or is eligible to be) its own ItemUI.
        /// </summary>
        /// <param name="item">The item to test.</param>
        /// <returns>True if the item is (or is eligible to be) its own ItemUI.</returns>
        protected override bool IsItemItsOwnContainerOverride(object item)
        {
            return item is RibbonComboBoxItem;
        }

        /// <summary>
        ///   Create or identify the element used to display the given item.
        /// </summary>
        /// <returns>The element used to display the given item.</returns>
        protected override DependencyObject GetContainerForItemOverride()
        {
            return new RibbonComboBoxItem();
        }

        /// <summary>
        ///   Called when the selection is changed.  Whenever selection changes in a
        ///   RibbonComboBox, we execute a command to "commit" the preview associated
        ///   with the currently selected RibbonComboBoxItem.
        /// </summary>
        /// <param name="e">Data associated with the SelectionChanged event.</param>
        protected override void OnSelectionChanged(SelectionChangedEventArgs e)
        {
            base.OnSelectionChanged(e);

            RibbonComboBoxItem item = this.GetHighlightedComboBoxItem();

            RibbonCommandParameter parameter = new RibbonCommandParameter()
            {
                CommandParameter = this.CommandParameter,
                Action = RibbonCommandAction.CommitPreview,
                ActionParameter = item,
            };

            CommandHelpers.ExecuteCommandSource(parameter, this);
        }

        #endregion

        #region Private Methods

        /// <summary>
        ///   If the Command property changes, we need to coerce some RibbonControl
        ///   specific properties to update their 'back-up' values coming from Command.
        /// </summary>
        /// <param name="d">The RibbonComboBox on which the Command property has changed value.</param>
        /// <param name="e">
        ///   Event data that is issued by any event that tracks changes to the effective value of this property.
        /// </param>
        private static void OnCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            RibbonComboBox comboBox = (RibbonComboBox)d;
            comboBox.CoerceValue(ToolTipProperty);
        }

        /// <summary>
        ///   Searches through the RibbonComboBox to find the currently highlighted item.
        /// </summary>
        /// <returns>Returns the currently highlighted RibbonComboBoxItem if one exits, otherwise null.</returns>
        private RibbonComboBoxItem GetHighlightedComboBoxItem()
        {
            RibbonComboBoxItem highlightedItem = null;

            foreach (RibbonComboBoxItem item in Items)
            {
                if (item.IsHighlighted)
                {
                    highlightedItem = item;
                    break;
                }
            }

            return highlightedItem;
        }

        #endregion

        // TODO - Try to get rid of this property
        #region Internal Attached Properties
        
        public static bool GetIsToggleButtonHighlighted(DependencyObject obj)
        {
            return (bool)obj.GetValue(IsToggleButtonHighlightedProperty);
        }

        public static void SetIsToggleButtonHighlighted(DependencyObject obj, bool value)
        {
            obj.SetValue(IsToggleButtonHighlightedProperty, value);
        }

        public static readonly DependencyProperty IsToggleButtonHighlightedProperty =
                    DependencyProperty.RegisterAttached(
                            "IsToggleButtonHighlighted",
                            typeof(bool),
                            typeof(RibbonComboBox),
                            new UIPropertyMetadata(false));

        #endregion
    }
}